import { Button, Input, Layout, message, Popconfirm, Typography } from "antd";
import { CloseCircleOutlined } from "@ant-design/icons";
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import { addLinkman, getLinkman, getMessageList, readMessage, removeLinkman, sendToFriend } from "src/api/chat";
import UserNameSelect from "src/components/dataEntry/UserNameSelect";
import EllipsisText from "@/components/dataPresentation/EllipsisText";
import { AppContext, ReceivedMessage } from "src/providers";
import { addChatItem, genLongerArray, getChatRecords, getImageUrl } from "src/util";
import { AdminRecord, MessageRecord, RecordListItem } from "../admin/AdminType";
import { EmojiWrapper, StyledChatItem } from "./AdminChat.styled";
import EmptyChat from "./components/EmptyChat";
import { ReactComponent as SmileEmoji } from "src/asset/smileEmoji.svg";
import { faces } from "src/asset/data/emoji";
import { cloneDeep, debounce } from "lodash";
import "dayjs/locale/zh-cn";
import dayjs from "dayjs";

const AdminChat = () => {
	const { themeCongifg, userInfo, receivedMessage } = useContext(AppContext);
	const [linkmans, setLinkmans] = useState<AdminRecord[]>([]);
	const [messageList, setMessageList] = useState<MessageRecord[]>([]);
	const primaryColor = useMemo(() => themeCongifg?.token?.colorPrimary || "#3C89FF", [themeCongifg]);
	const [activeId, setActiveId] = useState<null | string>(null);
	const [chatInputValue, setChatInputValue] = useState("");
	const inputWrapperRef = useRef<HTMLDivElement | null>(null);
	const [currentRecordList, setCurrentRecordList] = useState<RecordListItem[]>([]);
	const listDomRef = useRef<HTMLDivElement | null>(null);
	const getInitialPageOptions = () => ({ page: 1, pageSize: 10 });
	const pageOptions = useRef(getInitialPageOptions());
	const previousScrollHeight = useRef(0);
	const userNameChange = (admin?: AdminRecord) => {
		if (admin) {
			if (linkmans.find((menu) => menu._id === admin._id)) {
				setActiveId(admin._id);
			} else {
				addLinkman({ linkman: admin._id }).then(async () => {
					await initData();
					message.success("已添加");
				});
			}
			getRecords(admin._id);
			scrollListToBottom();
		}
	};
	const scrollListToBottom = () => {
		setTimeout(() => {
			if (listDomRef.current) {
				listDomRef.current.scrollTop = listDomRef.current.scrollHeight - listDomRef.current.clientHeight;
			}
		});
	};
	const getRecords = useCallback(
		(linkId?: string) => {
			if (!linkId && !activeId) return;
			const { page, pageSize } = pageOptions.current;
			const list = getChatRecords({ adminId: userInfo?._id, linkId: (linkId || activeId) as string, page, pageSize });
			if (page === 1) {
				setCurrentRecordList(list);
			} else {
				if (!list.length) pageOptions.current = { ...pageOptions.current, page: pageOptions.current.page - 1 };
				setCurrentRecordList(list.concat(currentRecordList));
			}
		},
		[activeId, userInfo, currentRecordList]
	);
	const fetchMessageList = async () => {
		await getMessageList().then((res) => {
			setMessageList(res?.data || []);
		});
	};
	const initData = async () => {
		await getLinkman().then((res) => {
			setLinkmans(res?.data?.data || []);
		});
		await fetchMessageList();
	};
	const clickEmoji = (face: { emoji: string; dec: string; Hex: string }) => {
		const messgeInput = inputWrapperRef.current?.children[0] as HTMLInputElement;
		const selectionStart = messgeInput.selectionStart;
		const selectionEnd = messgeInput.selectionEnd;
		let finalString = chatInputValue;
		let splitList: string[] = [];
		if (typeof selectionStart === "number" && selectionStart === selectionEnd) {
			splitList = [finalString.substring(0, selectionStart), finalString.substring(selectionStart)];
		}
		if (typeof selectionStart === "number" && typeof selectionEnd === "number" && selectionStart !== selectionEnd) {
			splitList = [finalString.substring(0, selectionStart), finalString.substring(selectionEnd)];
		}
		if (splitList.length === 2) {
			finalString = splitList[0] + face.emoji + splitList[1];
		}
		setChatInputValue(finalString);
		if (typeof selectionStart === "number") {
			messgeInput.focus();
		}
	};
	const handleSend = () => {
		if (!chatInputValue || !activeChatItem || !userInfo?._id) return;
		sendToFriend({ to: activeChatItem._id, content: chatInputValue }).then(async () => {
			addChatItem({
				adminId: userInfo._id || null,
				linkId: activeChatItem._id,
				content: chatInputValue,
				type: 1,
				avatar: userInfo?.avatar || "",
			});
			pageOptions.current = getInitialPageOptions();
			getRecords();
			if (userInfo._id === activeChatItem._id) await readMessage({ from: userInfo._id });
			scrollListToBottom();
			fetchMessageList();
			setChatInputValue("");
		});
	};
	const clickAdmin = useCallback(
		async (admin: MessageRecord | AdminRecord) => {
			if (activeId === admin._id) return;
			setActiveId(admin._id);
			pageOptions.current = getInitialPageOptions();
			//已读左侧消息列表
			if (messageList.find((message) => message._id === admin._id)) {
				await readMessage({ from: admin._id });
				await fetchMessageList();
			} else {
				// 消息列表未找到联系人则把该联系人加进消息列表
				const copiedMessageList = cloneDeep(messageList);
				type CopiedAdmin = Omit<AdminRecord, "createdTime"> & { createdTime?: string };
				const copiedAdmin: CopiedAdmin = cloneDeep(admin);
				delete copiedAdmin.createdTime;
				copiedMessageList.push({
					...admin,
					content: "",
					from: userInfo?._id,
					to: admin._id,
					updatedTime: Date.now().toString(),
					unRead: 0,
				});
				setMessageList(copiedMessageList);
			}
			getRecords(admin._id);
			scrollListToBottom();
		},
		[messageList, userInfo, activeId]
	);
	const activeChatItem = useMemo<MessageRecord | null>(() => {
		return messageList.find((message) => message._id === activeId) || null;
	}, [activeId, messageList]);
	const calcTimeShow = (recordIndex: number) => {
		if (recordIndex === 0) return true;
		const lastRecord = currentRecordList[recordIndex - 1];
		const lastTime = new Date(lastRecord.timeStamp).getTime();
		const currentTime = new Date(currentRecordList[recordIndex].timeStamp).getTime();
		if (recordIndex === currentRecordList.length - 1) {
			return Date.now() - currentTime > 5 * 60 * 1000;
		}
		return currentTime - lastTime > 5 * 60 * 1000;
	};
	const readMessageDebounce = useCallback(
		debounce(async () => {
			if (!activeId) return;
			await readMessage({ from: activeId });
			await fetchMessageList();
		}, 1000),
		[activeId]
	);
	useEffect(() => {
		initData();
	}, []);
	useEffect(() => {
		if (receivedMessage !== null) {
			if (Object.prototype.toString.call(receivedMessage) === "[object Object]") {
				const { adminId, linkId } = receivedMessage as ReceivedMessage;
				if (adminId === linkId) return;
				addChatItem(receivedMessage as ReceivedMessage);
			}
			if (Object.prototype.toString.call(receivedMessage) === "[object Array]") {
				(receivedMessage as ReceivedMessage[]).forEach((item) => {
					addChatItem(item);
				});
			}
			getRecords();
			scrollListToBottom();
			fetchMessageList();
			readMessageDebounce();
		}
	}, [receivedMessage]);
	return (
		<div>
			<Layout style={{ height: "calc(100vh - 64px - 24px * 2 - 16px * 2)" }}>
				<Layout.Sider theme="light" width={220} className="pr-4">
					<Typography.Title level={5} className="mt-2 text-center">
						最近消息
					</Typography.Title>
					<div className="relative">
						{messageList.map((admin, index) => (
							<StyledChatItem
								primaryColor={primaryColor}
								active={admin._id === activeId}
								onClick={() => clickAdmin(admin)}
								key={index}
								className="border flex items-center p-2 cursor-pointer rounded"
							>
								<img className="mr-2 rounded" width={42} src={getImageUrl(admin?.avatar || "")} />
								<div className="flex flex-col justify-between h-[42px]" style={{ minWidth: "120px", maxWidth: "140px" }}>
									<EllipsisText className="font-bold">{admin?.username}</EllipsisText>
									<EllipsisText className="text-gray-500">{admin?.content}</EllipsisText>
								</div>
								{admin.unRead !== 0 && (
									<div
										className="bg-red-500 text-white flex justify-center items-center rounded-full text-xs self-end"
										style={{ width: admin.unRead && +admin.unRead > 99 ? "30px" : "17px", height: "17px" }}
									>
										{admin.unRead && (+admin.unRead > 99 ? "99+" : admin.unRead)}
									</div>
								)}
							</StyledChatItem>
						))}
					</div>
				</Layout.Sider>
				<Layout.Sider theme="light" width={220} className="pr-4">
					<Typography.Title level={5} className="mt-2 text-center">
						联系人列表
					</Typography.Title>
					<UserNameSelect
						style={{ width: "100%" }}
						optionValueKey="_id"
						placeholder="搜索用户添加为联系人"
						reflexItem={userNameChange}
					/>
					<div className="mt-2 relative">
						{linkmans.map((admin, index) => (
							<StyledChatItem
								primaryColor={primaryColor}
								active={admin._id === activeId}
								onClick={() => clickAdmin(admin)}
								key={index}
								className="border flex items-center p-1 cursor-pointer rounded"
							>
								<img className="mr-2 rounded" width={40} src={getImageUrl(admin?.avatar || "")} />
								<div style={{ minWidth: "120px", maxWidth: "140px" }}>
									<EllipsisText className="font-bold">{admin?.username}</EllipsisText>
								</div>
								<Popconfirm
									title={`确定要移除${admin.username}吗？`}
									onConfirm={() => {
										removeLinkman({ linkman: admin._id }).then(async () => {
											await initData();
											message.success("已移除");
										});
									}}
								>
									<CloseCircleOutlined className="absolute right-3 closeIcon" style={{ color: "#f71e1e" }} />
								</Popconfirm>
							</StyledChatItem>
						))}
					</div>
				</Layout.Sider>
				<Layout className="site-layout">
					<Layout.Content className="border">
						{!activeId && <EmptyChat />}
						{!!activeId && (
							<div className="relative h-full w-full">
								<div className="w-full bg-white flex justify-center">
									<EllipsisText
										className="w-1/3 py-2 text-xl text-center"
										overlay={genLongerArray(10, activeChatItem?.username).toString()}
									>
										{activeChatItem?.username}
									</EllipsisText>
								</div>
								<div
									ref={listDomRef}
									onScroll={(e) => {
										const { scrollTop, scrollHeight } = e.target as HTMLDivElement;
										if (scrollTop === 0) {
											previousScrollHeight.current = scrollHeight;
											const { page } = pageOptions.current;
											pageOptions.current = { ...pageOptions.current, page: page + 1 };
											getRecords();
											setTimeout(() => {
												if (!listDomRef.current) return;
												listDomRef.current.scrollTop =
													listDomRef.current.scrollHeight - previousScrollHeight.current;
											});
										}
									}}
									className="w-full overflow-y-scroll p-3 rounded"
									style={{ height: "calc(100% - 100px)" }}
								>
									{currentRecordList.map((record, recordIndex) => (
										<div key={recordIndex} className="mb-3">
											<div
												className="flex items-start"
												style={{ flexDirection: record.type === 2 ? "row" : "row-reverse" }}
											>
												<img
													className="rounded-full border border-2 border-white shadow-sm border-solid shrink-0 overflow-hidden mt-1"
													width={45}
													height={45}
													src={getImageUrl(record.avatar)}
												/>
												<div
													className={`flex-1 flex flex-col ${
														record.type === 2 ? "items-start ml-3" : "items-end mr-3"
													}`}
												>
													<div className="bg-white py-2 px-3 rounded mt-2">{record.content}</div>
												</div>
											</div>
											{calcTimeShow(recordIndex) && (
												<div className="text-center my-4 text-gray-400 select-none">
													{dayjs(record.timeStamp).fromNow()}
												</div>
											)}
										</div>
									))}
								</div>
								<div className="py-3 px-2 w-full bg-white absolute bottom-0 flex items-center">
									<EmojiWrapper className="mr-2 flex justify-center items-center relative">
										<div
											className="emojiArea absolute"
											style={{ left: "-5px", top: "-220px", width: "524px", height: "220px" }}
										>
											<div className=" overflow-y flex rounded flex-wrap overflow-y-scroll justify-between bg-white mb-5">
												{faces.map((face, faceIndex) => (
													<div className="p-3 text-xl" key={faceIndex}>
														<span onClick={() => clickEmoji(face)} className="cursor-pointer">
															{face.emoji}
														</span>
													</div>
												))}
												{Array.from({ length: 11 - (faces.length % 11) }, (_, index) => index).map((remain) => (
													<div key={remain} style={{ width: "44px" }} />
												))}
											</div>
										</div>
										<SmileEmoji className="cursor-pointer" width={25} height={25} />
									</EmojiWrapper>
									<div ref={inputWrapperRef} className="flex-1">
										<Input
											value={chatInputValue}
											onPressEnter={handleSend}
											onChange={(e) => setChatInputValue(e.target.value)}
										/>
									</div>
									<Button type="primary" className="ml-3" onClick={handleSend}>
										发送
									</Button>
								</div>
							</div>
						)}
					</Layout.Content>
				</Layout>
			</Layout>
		</div>
	);
};

export default AdminChat;
